home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / mega src / Source / mv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-17  |  10.5 KB  |  435 lines  |  [TEXT/KAHL]

  1. /* ========== the commmand file: ==========
  2.  
  3.     mv.c
  4.     
  5.     Copyright (c) 1993,1994 Newport Software Development
  6.     
  7.     You may distribute unmodified copies of this file for
  8.     noncommercial purposes.  You may use this file as a
  9.     reference when writing your own nShell(tm) commands.
  10.     
  11.     All other rights are reserved.
  12.     
  13.    ========== the commmand file: ========== */
  14.  
  15. #include "nshc.h"
  16.  
  17. #include "arg_utl.proto.h"
  18. #include "fss_utl.proto.h"
  19. #include "fss_utl2.proto.h"
  20. #include "nshc_utl.proto.h"
  21. #include "str_utl.proto.h"
  22.  
  23. // data definition - this struct is the root of all data
  24.  
  25. typedef struct {
  26.  
  27.     int        arg;            // position in arg list
  28.     
  29.     int        got_fss;
  30.     
  31.     Boolean    isDir;            // if target is a directory
  32.     long    dirID;            // id of target if it is a directory
  33.  
  34.     FSSpec    toSpec;            // fsspec of output file
  35.     
  36. } t_mv_data;
  37.  
  38. typedef    t_mv_data    **CDataH;
  39.  
  40. /* ======================================== */
  41.  
  42. // prototypes - utility
  43.  
  44. void mv_bad( t_nshc_parms *nshc_parms, int code );
  45. void mv_bad_file( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, StringPtr msg );
  46. void mv_good( t_nshc_parms *nshc_parms );
  47.  
  48. // prototypes - file routines
  49.  
  50. void  mv_make_name( Str63 name );
  51. OSErr mv_clear_init(const FSSpec *spec);
  52. OSErr mv_move(FSSpec *fromSpec, FSSpec *toSpec, t_nshc_calls *nshc_calls);
  53. void  mv_setup( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_mv_data **hData );
  54. void  mv_task( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_mv_data **hData );
  55.  
  56. // prototypes - state machine
  57.  
  58. void mv_start( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls  );
  59. void mv_continue( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  60. void mv_stop( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  61.  
  62. /* ======================================== */
  63.  
  64. // utility routines
  65.  
  66. /* ======================================== */
  67.  
  68. void mv_bad(  t_nshc_parms *nshc_parms, int code )
  69. {
  70.     nshc_parms->action = nsh_stop;
  71.     nshc_parms->result = code;
  72. }
  73.  
  74. void mv_bad_file(  t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, StringPtr msg )
  75. {
  76.     nshc_calls->NSH_putStr_err("\pmv: File access error (");
  77.     nshc_calls->NSH_putStr_err(msg);
  78.     nshc_calls->NSH_putStr_err("\p)\r");
  79.  
  80.     nshc_parms->action = nsh_stop;
  81.     nshc_parms->result = NSHC_ERR_GENERAL;
  82. }
  83.  
  84. void mv_good(  t_nshc_parms *nshc_parms )
  85. {
  86.     nshc_parms->action = nsh_stop;
  87.     nshc_parms->result = 0;
  88. }
  89.  
  90. /* ======================================== */
  91.  
  92. // file access routines
  93.  
  94. /* ======================================== */
  95.  
  96. OSErr mv_clear_init(const FSSpec *spec)
  97. {
  98.     CInfoPBRec pb;
  99.     OSErr result;
  100.  
  101.     pb.hFileInfo.ioNamePtr = (StringPtr)spec->name;
  102.     pb.hFileInfo.ioVRefNum = spec->vRefNum;
  103.     pb.hFileInfo.ioDirID = spec->parID;
  104.     pb.hFileInfo.ioFDirIndex = 0;
  105.  
  106.     result = PBGetCatInfoSync(&pb);
  107.  
  108.     if (!result) {
  109.         pb.hFileInfo.ioFlFndrInfo.fdFlags = pb.hFileInfo.ioFlFndrInfo.fdFlags & 0xfeff;
  110.         pb.hFileInfo.ioDirID = spec->parID;
  111.         result = PBSetCatInfoSync(&pb);    /* now, save the new information back to disk */
  112.         }
  113.         
  114.     return (result);
  115. }
  116.  
  117. /* ======================================== */
  118.  
  119. void mv_setup( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_mv_data **hData )
  120. {
  121.     int        argc;
  122.     int        result;
  123.     char    *toStr;
  124.     
  125.     (**hData).arg = 1;                    // start at the arg = 1 position
  126.     (**hData).got_fss = fss_test();        // remember if fsspecs are available
  127.  
  128.     // strip off target path and process it
  129.  
  130.     argc = --nshc_parms->argc;
  131.     
  132.     toStr = &nshc_parms->arg_buf[ nshc_parms->argv[argc] ];
  133.     
  134.     if ( cStrEqual( toStr, "dev:tty" ) ) {
  135.         nshc_calls->NSH_putStr_err( "\pmv: \"dev:tty\" is not supported.\r" );
  136.         mv_bad( nshc_parms, NSHC_ERR_PARMS );
  137.         return;
  138.         }
  139.  
  140.     if ( cStrEqual( toStr, "dev:null" ) ) {
  141.         nshc_calls->NSH_putStr_err( "\pmv: \"dev:null\" is not supported.\r" );
  142.         mv_bad( nshc_parms, NSHC_ERR_PARMS );
  143.         return;
  144.         }
  145.         
  146.     result = arg_to_fss( nshc_parms, nshc_calls, argc, &(**hData).toSpec );
  147.     
  148.     if (result)
  149.         mv_bad( nshc_parms, result );
  150.     else{
  151.         result = fss_to_DirID( &(**hData).toSpec, &(**hData).dirID, &(**hData).isDir );
  152.         if (argc > 2) {
  153.             if ( (result != noErr) || !(**hData).isDir ) {
  154.                 nshc_calls->NSH_putStr_err( "\pmv: Destination must be a directory when more than one file is moved.\r" );
  155.                 mv_bad( nshc_parms, NSHC_ERR_PARMS );
  156.                 }
  157.             }
  158.         else {
  159.             if ( (result == noErr) && !(**hData).isDir ) {
  160.                 nshc_calls->NSH_putStr_err("\pmv: File already exists (");
  161.                 nshc_calls->NSH_putStr_err((StringPtr)(**hData).toSpec.name);
  162.                 nshc_calls->NSH_putStr_err("\p)\r");
  163.                 mv_bad( nshc_parms, NSHC_ERR_PARMS );
  164.                 }
  165.             }
  166.         }
  167. }
  168.  
  169. /* ========================================== */
  170.  
  171. void mv_make_name( Str63 name )
  172. {
  173.     char    temp[20];
  174.     int        i,j;
  175.     long    ticks;
  176.     
  177.     i = 0;
  178.     ticks = TickCount();
  179.     
  180.     while (ticks) {
  181.         temp[i++] = '0' + ticks % 10;
  182.         ticks = ticks / 10;
  183.         }
  184.     
  185.     name[0] = 4 + i;
  186.     name[1] = 't';
  187.     name[2] = 'm';
  188.     name[3] = 'p';
  189.     name[4] = '.';
  190.     
  191.     j = 5;
  192.     while (i--)
  193.         name[j++] = temp[i];
  194. }
  195.     
  196. OSErr mv_move(FSSpec *fromSpec, FSSpec *toSpec, t_nshc_calls *nshc_calls)
  197. {
  198.     CMovePBRec        pb;
  199.     HParamBlockRec    hpb;
  200.     OSErr            result;
  201.     int                retries;
  202.     Str63            temp_name;
  203.     Str63            save_name;
  204.     
  205.     if ( fromSpec->parID != toSpec->parID ) {
  206.     
  207.         retries = 0;
  208.         result = 0;
  209.     
  210.         do {
  211.         
  212.             if (retries) {
  213.                 if (retries == 1)
  214.                     pStrCopy( save_name, (StringPtr) &(fromSpec->name) );
  215.                 mv_make_name( temp_name );
  216.                 hpb.fileParam.ioDirID = fromSpec->parID;
  217.                 hpb.ioParam.ioMisc = (Ptr)temp_name;
  218.                 hpb.ioParam.ioNamePtr = (StringPtr) &(fromSpec->name);
  219.                 hpb.ioParam.ioVersNum = 0;
  220.                 hpb.ioParam.ioVRefNum = fromSpec->vRefNum;
  221.                 result = PBHRenameSync(&hpb);
  222.                 if ( !result )
  223.                     pStrCopy( (StringPtr) &(fromSpec->name), temp_name );
  224.                 }
  225.  
  226.             if ( !result ) {
  227.                 pb.ioDirID = fromSpec->parID;
  228.                 pb.ioNamePtr = (StringPtr) &(fromSpec->name);
  229.                 pb.ioNewDirID = toSpec->parID;
  230.                 pb.ioNewName = nil;
  231.                 pb.ioVRefNum = fromSpec->vRefNum;
  232.                 result = PBCatMoveSync(&pb);
  233.                 }
  234.             
  235.             retries++;
  236.     
  237.         } while (( retries < 11) && (result == dupFNErr));
  238.         
  239.         if ( result ) {
  240.             if ( !pStrEqual( (StringPtr)&(fromSpec->name), save_name ) ) {
  241.                 hpb.fileParam.ioDirID = fromSpec->parID;
  242.                 hpb.ioParam.ioMisc = (Ptr)save_name;
  243.                 hpb.ioParam.ioNamePtr = (StringPtr) &(fromSpec->name);
  244.                 hpb.ioParam.ioVersNum = 0;
  245.                 hpb.ioParam.ioVRefNum = fromSpec->vRefNum;
  246.                 PBHRenameSync(&hpb);
  247.                 }
  248.             return( result );
  249.             }
  250.             
  251.         }
  252.     
  253.     if ( pStrEqual( (StringPtr) &(fromSpec->name), (StringPtr) &(toSpec->name) ) )
  254.         return( noErr );
  255.         
  256.     hpb.fileParam.ioDirID = toSpec->parID;
  257.     hpb.ioParam.ioMisc = (Ptr)&(toSpec->name);
  258.     hpb.ioParam.ioNamePtr = (StringPtr) &(fromSpec->name);
  259.     hpb.ioParam.ioVersNum = 0;
  260.     hpb.ioParam.ioVRefNum = toSpec->vRefNum;
  261.     
  262.     return( PBHRenameSync(&hpb) );
  263. }
  264.  
  265. /* ======================================== */
  266.  
  267. void mv_task( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_mv_data **hData )
  268. {
  269.     int        result;
  270.     long    dirID;
  271.     Boolean    isDir;
  272.     FInfo    fndrInfo;
  273.     FSSpec    fromSpec;
  274.     
  275.     // =====> convert "from" path to fsspec
  276.     
  277.     result = arg_to_fss( nshc_parms, nshc_calls, (**hData).arg, &fromSpec );
  278.     
  279.     (**hData).arg++;
  280.     
  281.     if (result) {
  282.         mv_bad( nshc_parms, result );
  283.         return;
  284.         }
  285.     
  286.     if (fromSpec.vRefNum != (**hData).toSpec.vRefNum) {
  287.         nshc_calls->NSH_putStr_err("\pmv: File must be on destination volume (");
  288.         nshc_calls->NSH_putStr_err((StringPtr)fromSpec.name);
  289.         nshc_calls->NSH_putStr_err("\p)\r");
  290.         mv_bad( nshc_parms, NSHC_ERR_GENERAL );
  291.         return;
  292.         }
  293.         
  294.     result = fss_to_DirID( &fromSpec, &dirID, &isDir );
  295.         
  296.     if ( result == fnfErr ) {
  297.         nshc_calls->NSH_putStr_err("\pmv: File not found (");
  298.         nshc_calls->NSH_putStr_err((StringPtr)fromSpec.name);
  299.         nshc_calls->NSH_putStr_err("\p)\r");
  300.         mv_bad( nshc_parms, NSHC_ERR_GENERAL );
  301.         return;
  302.         }
  303.             
  304.     if ( result ) {
  305.         mv_bad_file( nshc_parms, nshc_calls, (StringPtr)fromSpec.name );
  306.         return;
  307.         }
  308.             
  309.     // =====> if the target is a dir, construct and test full target path
  310.         
  311.     if ((**hData).isDir) {
  312.     
  313.         (**hData).toSpec.parID = (**hData).dirID;
  314.         pStrCopy( (**hData).toSpec.name, fromSpec.name );
  315.         
  316.         if ( !fss_to_DirID( &(**hData).toSpec, &dirID, &isDir ) ) {
  317.             if (isDir)
  318.                 nshc_calls->NSH_putStr_err("\pmv: Folder already exists (");
  319.             else
  320.                 nshc_calls->NSH_putStr_err("\pmv: File already exists (");
  321.             nshc_calls->NSH_putStr_err((StringPtr)(**hData).toSpec.name);
  322.             nshc_calls->NSH_putStr_err("\p)\r");
  323.             mv_bad( nshc_parms, NSHC_ERR_GENERAL );
  324.             return;
  325.             }
  326.         }
  327.         
  328.     // =====> move it
  329.     
  330.     HLock( hData );
  331.     result =  mv_move( &fromSpec, &(**hData).toSpec, nshc_calls );
  332.     HUnlock( hData );
  333.     
  334.     if (result) {
  335.         nshc_calls->NSH_putStr_err( "\pmv: Could not move file (");
  336.         nshc_calls->NSH_putStr_err((StringPtr)(**hData).toSpec.name);
  337.         nshc_calls->NSH_putStr_err("\p)\r");
  338.         mv_bad( nshc_parms, NSHC_ERR_PARMS );
  339.         return;
  340.         }
  341.         
  342.     // =====> and tell the findir to init it
  343.     
  344.     result =  mv_clear_init( &(**hData).toSpec );
  345.  
  346.     if (result)
  347.         nshc_calls->NSH_putStr_err( "\pmv: Warning - could not position icon.\r" );
  348.         
  349.     result = fss_wake_parent( &(**hData).toSpec );
  350.  
  351.     if (result)
  352.         nshc_calls->NSH_putStr_err( "\pmv: Warning - could update finder info.\r" );
  353. }
  354.  
  355. /* ======================================== */
  356.  
  357. // state machine - core routines
  358.  
  359. /* ======================================== */
  360.  
  361. void mv_start( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls  )
  362. {
  363.     CDataH    hData;    // handle to hold our data
  364.     
  365.     if (nshc_parms->argc < 3) {
  366.         nshc_calls->NSH_putStr_err( "\pUsage: see \"man mv\" for options.\r" );
  367.         mv_bad( nshc_parms, NSHC_ERR_PARMS );
  368.         return;
  369.         }
  370.         
  371.     nshc_parms->action = nsh_continue;
  372.  
  373.     hData = (CDataH)NewHandleClear(sizeof(t_mv_data));
  374.     
  375.     if (hData) {
  376.         HLock( hData );
  377.         mv_setup( nshc_parms, nshc_calls, hData );
  378.         HUnlock( hData );
  379.         nshc_parms->data = (Handle)hData;
  380.         }
  381.     else {
  382.         nshc_calls->NSH_putStr_err( "\pmv: Could not allocate storage.\r" );
  383.         mv_bad( nshc_parms, NSHC_ERR_MEMORY );
  384.         }
  385. }
  386.  
  387. /* ======================================== */
  388.  
  389. void mv_continue( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  390. {
  391.     CDataH    hData;
  392.     
  393.     if (hData = (CDataH)nshc_parms->data) {
  394.     
  395.         if ((**hData).arg >= nshc_parms->argc)
  396.             mv_good( nshc_parms );
  397.         else
  398.             mv_task( nshc_parms, nshc_calls, hData );
  399.             
  400.         }
  401.     else
  402.         nshc_parms->action = nsh_idle;
  403. }
  404.  
  405. /* ======================================== */
  406.  
  407. void mv_stop( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  408. {
  409.     if ( nshc_parms->data )        
  410.         DisposeHandle(nshc_parms->data);
  411.         
  412.     nshc_parms->action = nsh_idle;
  413. }
  414.  
  415. /* ======================================== */
  416.  
  417. void main(t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls)
  418. {
  419.     if (nshc_bad_version( nshc_parms, nshc_calls, NSHC_VERSION )) return;
  420.     
  421.     switch (nshc_parms->action) {
  422.         case nsh_start:
  423.             mv_start(nshc_parms, nshc_calls);
  424.             break;
  425.         case nsh_continue:
  426.             mv_continue(nshc_parms, nshc_calls);
  427.             break;
  428.         case nsh_stop:
  429.             mv_stop(nshc_parms, nshc_calls);
  430.             break;
  431.         }
  432. }
  433.  
  434. /* ======================================== */
  435.